package itsur.arquitecturas.implicitinvocation;

/**************************************************************************************
** Class name: RegisterStudent
** Author: A.J. Lattanze
** Date: 12/29/99
** Version 1.0
***************************************************************************************
** Purpose: Assignment 3 for SE 17-655, Architectures for Software Systems. This method
** will register students for courses.
**
** Abstract:When notified, the current list of students is displayed for the user, by
** sending an event with the ListStudents ID.  The user is then prompted to enter a
** student ID.  After entering the student ID, the current list of courses is displayed
** for the user, by sending an event with the ListCourses ID.  The user is then prompted
** to enter a the course number and section. After entering the student ID student will
** be registered for the course.
**
** Modification Log
**************************************************************************************
** Modification by: A.J. Lattanze
** Date: 01/24/02
** Version 1.5
** Description: This class has been changed to run as a stand-alone thread. This
** method was changed to implement the Runnable class so that it could run as a thread.
** While, this has little impact on the architecture, it illustrates a multi-threaded
** event model.
**************************************************************************************
** Modification by: ITSUR
** Date: 03/12/08
** Version 1.5
** Description: This class has been changed to validate Schedule conflicts when register 
** a course for a student.  Validates that the course is trying to register is not in 
** the same day and hour of a course already registered for the student.
**************************************************************************************/
import java.util.*;

public class RegisterStudentIntelliSection extends Communication implements Runnable
{
	boolean Stop = false;

	public RegisterStudentIntelliSection( Integer RegistrationNumber, String ComponentName )
	{
		super( RegistrationNumber, ComponentName );

	} // Constructor

	public void update( Observable Thing, Object NotificationNumber )
	{
		Menus Menu = new Menus();
		Displays Display = new Displays();
		Student MyStudent = new Student();
		Course MyCourse = new Course();

		// The update() method is an abstract method that is called whenever the
		// notifyObservers() method is called by the Observable class
		// First we check to see if the NotificationNumber is equal to this
		// thread's RegistrationNumber or SYSTEM_SHUT_DOWN.  If they are, then we
		// execute - otherwise, we stay idle.

		if ( RegistrationNumber.compareTo(NotificationNumber) == 0 )
		{
			AddToReceiverList( "ListStudentsComponent" );
			AddToReceiverList( "ListCoursesComponent" );

			// Display the students and prompt the user to pick a student

			SignalReceivers( "ListStudentsComponent" );

			MyStudent = Menu.PickStudent( SystemData.TheListOfStudents.ListOfStudents );

			if ( MyStudent != null )
			{
				// Display the courses that are available and ask the user to pick a
				// course to register for

				SignalReceivers( "ListCoursesComponent" );

				MyCourse = Menu.PickCourseWithoutSection( SystemData.TheListOfCourses.ListOfCourses );

				if ( MyCourse != null )
				{
				   // If the selected course and student exist, then complete the
				   // registration process.

					//ITSUR Evitar que el estudiante se registre mas de una vez a la misma clase
					CourseList coreCourses = SystemData.TheListOfCourses.ListOfCourses;
					Course CourseObject = null;
					boolean registroExitoso=false;

					coreCourses.GoToFrontOfList();
					while ((CourseObject = coreCourses.GetNextCourse()) != null) {
						if(CourseObject.CourseID.equals(MyCourse.CourseID))//
							if(courseValidation(MyStudent, CourseObject)){
								   MyCourse.Register( MyStudent );
								   MyStudent.Register( CourseObject );
								   registroExitoso=true;
								   break;
							}
					} // while
					
					
					if(!registroExitoso){
						System.out.println( "\n\n *** Course can't be registered ***" );
					}else{
						System.out.println( "\n\n *** The student has been registered in the course  ***" );
						System.out.println( CourseObject.CourseName + " " + CourseObject.CourseID + " " + CourseObject.Section + " " + CourseObject.Days + " " + CourseObject.StartTime + ":" + CourseObject.StopTime + " " + CourseObject.Instructor);
					}
					
				} else {

				   System.out.println( "\n\n *** Course not found ***" );


				} // if

			} else {

				System.out.println( "\n\n *** Student not found ***" );

			} // if

		} // if

		if ( SYSTEM_SHUT_DOWN_ID.compareTo(NotificationNumber) == 0 )
		{
			Stop = true;

		} // if

		RemoveFromReceiverList( "ListCoursesComponent" );
		RemoveFromReceiverList( "ListStudentsComponent" );

	} // update

	//ITSUR
	private boolean courseValidation(Student student, Course course){
		//Validar que no se encuentre ya en registrado al curso.
		if(student.CoursesRegistered.FindCourse(course)){ 
		   System.out.println("\n *** This student has already taken  \"" + course.CourseID + ":" + course.CourseName +  "\" course  ***");
		   return false;
		}
		
		
		//Validar que no existan cruce en dias y  horarios
		student.CoursesRegistered.GoToFrontOfList();
		Course courseRegistered;
		while ((courseRegistered = student.CoursesRegistered.GetNextCourse())!= null) {
			
			//Determinar si las materias se imparten el mismo dia.
			boolean sameDay = false; 
			
			
			boolean hasTuesday = false;
			try{
				int index = course.Days.indexOf("T");
				if((index != -1) && ((course.Days.charAt(index+1)) != 'R'))
					hasTuesday = true;
			}catch (Exception e) {
				// Do nothing
			}
			
			boolean[] courseDays = {
					course.Days.contains("M"), 
					hasTuesday,
					course.Days.contains("W"),
					course.Days.contains("TR"),
					course.Days.contains("F")};
			
			hasTuesday = false;
			try{
				int index = courseRegistered.Days.indexOf("T");
				if((index != -1) && ((courseRegistered.Days.charAt(index+1)) != 'R'))
					hasTuesday = true;
			}catch (Exception e) {
				// Do nothing
			}
			
			boolean[] courseRegisteredDays = {
					courseRegistered.Days.contains("M"), 
					hasTuesday,
					courseRegistered.Days.contains("W"),
					courseRegistered.Days.contains("TR"),
					courseRegistered.Days.contains("F")};
			
//			System.out.println("courseRegisteredDays");
//			for (int i = 0; i < courseRegisteredDays.length; i++) {
//				System.out.print(courseRegisteredDays[i] + " ");	
//			}
//
//			System.out.println("courseDays");
//			for (int i = 0; i < courseDays.length; i++) {
//				System.out.print(courseDays[i] + " ");	
//			}
			
			for (int i = 0; i < courseRegisteredDays.length; i++) {
				if (courseRegisteredDays[i] && courseDays[i]) {
					sameDay = true;
				}
			}
			
//			System.out.println("SameDay");
			
			if(sameDay){ //Si las materias se imparte el mismo dia revisar los horarios.
				int courseStartTime = Integer.parseInt(course.StartTime);
				int courseStopTime = Integer.parseInt(course.StopTime);
				int crStartTime = Integer.parseInt(courseRegistered.StartTime);
				int crStopTime = Integer.parseInt(courseRegistered.StopTime);
				
				//Si hay cruces de horarios imprimir lo siguiente.
				if((courseStartTime >= crStartTime) && (courseStartTime < crStopTime) ||
				   (courseStopTime > crStartTime) && (courseStopTime < crStopTime)||
				   (crStartTime >= courseStartTime) && (crStartTime < courseStopTime)||
				   (crStopTime > courseStartTime) && (crStopTime < courseStopTime)){
					System.out.println("\n *** Course Schedule Conflicts. This student is already registered in:");
					System.out.println( courseRegistered.CourseName + " " + courseRegistered.CourseID + " " + courseRegistered.Section + " " + courseRegistered.Days + " " + courseRegistered.StartTime + ":" + courseRegistered.StopTime + " " + courseRegistered.Instructor);
					System.out.println( "  can't be registered to:");
					System.out.println( course.CourseName + " " + course.CourseID + " " + course.Section + " " + course.Days + " " + course.StartTime + ":" + course.StopTime + " " + course.Instructor);
					System.out.println( " ***");
					return false;
				}
			}
		}

		return true;
	} 
	
	
	public void run()
	{
		System.out.println( "\nRegisterStudentIntelliSection Component Started..." );

		try
		{
			while( !Stop )
	        {
				// Note this is something of a farce here.  In order to start each
				// component as a separate thread, the run() method must be implemented.
	            // To illustrate how run() could be used here I put some code here.We really
	           	// don't do anything here,.. but we could.  If we were doing things here,
	           	// whatever it was that we were doing would be interrupted when an event
	           	// from the executive arrived, and the update() method we would immediately
	           	// execute. Currently we wait forever (by 1 second increments).  Please feel
	           	// free to put code if if you thing you need to (not to imply that you will
	           	// need to).

	           	Thread.sleep( 1000 );

	        } // while

	        System.out.println( "\nRegisterStudentIntelliSection Component Shutdown..." );


		} catch (Exception e) {

			System.out.println( "Exception occured in RegisterStudentIntelliSection.run(): " + e);

		}  // try-catch

	} // run
} // RegisterStudent